package drds.plus.executor.cursor.cursor.impl.sort;

import drds.plus.executor.cursor.column_index_mapping.ColumnIndexInTemplateCursorMetaDataToColumnIndexInRequestCursorMetaDataConvertor;
import drds.plus.executor.cursor.cursor.Cursor;
import drds.plus.executor.cursor.cursor.ISortingCursor;
import drds.plus.executor.cursor.cursor.impl.DuplicateValueRowDataLinkedList;
import drds.plus.executor.record_codec.record.Record;
import drds.plus.executor.row_values.RowValues;
import drds.plus.executor.utils.Utils;
import drds.plus.util.GeneralUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * n个cursor的归并排序，假设子cursor都是有序的
 */
public class SortedMergeCursors extends SortCursor {

    private final List<ISortingCursor> sortingCursorList;
    protected RowValues current = null;
    boolean allowDuplicated = false;
    boolean inited = false;
    RowValues currentMaxOrMinRowData = null;
    private ColumnIndexInTemplateCursorMetaDataToColumnIndexInRequestCursorMetaDataConvertor columnIndexInTemplateCursorMetaDataToColumnIndexInRequestCursorMetaDataConvertor;
    /**
     * 保存每个cursor当前的值得wrapper
     */
    private List<RowValues> rowDataList;
    private boolean templateIndexIsLeftIndex0 = true;

    public SortedMergeCursors(List<ISortingCursor> sortingCursorList, boolean duplicated) throws RuntimeException {
        super(sortingCursorList.get(0), null);
        this.sortingCursorList = sortingCursorList;
        this.allowDuplicated = duplicated;
        rowDataList = new ArrayList(sortingCursorList.size());
        this.orderByList = sortingCursorList.get(0).getOrderByList();
    }

    public SortedMergeCursors(ISortingCursor sortingCursor, boolean duplicated) throws RuntimeException {
        super(sortingCursor, null);
        List<ISortingCursor> cursorList = new ArrayList(1);
        cursorList.add(sortingCursor);

        this.sortingCursorList = cursorList;
        this.allowDuplicated = duplicated;
        rowDataList = new ArrayList(cursorList.size());
    }

    public void beforeFirst() throws RuntimeException {
        inited = false;
        rowDataList.clear();
        rowDataList = new ArrayList(sortingCursorList.size());
        for (Cursor cursor : sortingCursorList) {
            cursor.beforeFirst();
        }
    }

    public void init() throws RuntimeException {
        if (inited) {
            return;
        }
        inited = true;

        for (int i = 0; i < sortingCursorList.size(); i++) {
            RowValues rowData = sortingCursorList.get(i).next();
            rowData = wrapAndBuildColumnIndexToIndexInCursorMapIfNeed(rowData, i == 0);
            rowDataList.add(rowData);
        }
    }

    /**
     * values中存着每个cursor的当前值 每次调用next，从values中找出最小的值，并且将对应的cursor前移 将新值存到values中。如果去重，需要将重复的值略过
     */
    public RowValues next() throws RuntimeException {
        init();
        int indexOfCurrentMaxOrMinRowData = 0;
        currentMaxOrMinRowData = null;
        //
        for (int index = 0; index < this.rowDataList.size(); index++) {
            RowValues rowData = this.rowDataList.get(index);
            if (rowData == null) {
                continue;
            }
            if (currentMaxOrMinRowData == null) {
                currentMaxOrMinRowData = rowData;
                indexOfCurrentMaxOrMinRowData = index;
                continue;
            }
            //每次都要重新初始化进行再进行比较
            super.initComparator(orderByList, rowData.getParentCursorMetaData());
            int result = rowDataComparator.compare(rowData, currentMaxOrMinRowData);
            //
            if (result < 0) {
                currentMaxOrMinRowData = rowData;
                indexOfCurrentMaxOrMinRowData = index;
            } else if (result == 0) {
                if (!this.allowDuplicated) {
                    // [去重]cursor中重复的记录消耗光。随着游标的移动，最大的可能性会把所有的游标重复的数据耗尽。
                    RowValues duplicateRowDataOfNeedToRemove = null;//czh 原来的代码RowData duplicateRowDataOfNeedToRemove = currentMaxOrMinRowData
                    while (true) {
                        duplicateRowDataOfNeedToRemove = this.sortingCursorList.get(index).next();// i去重
                        if (duplicateRowDataOfNeedToRemove == null) {//[为null或者不等于上一个值则为新值]
                            break;
                        }
                        duplicateRowDataOfNeedToRemove = wrapAndBuildColumnIndexToIndexInCursorMapIfNeed(duplicateRowDataOfNeedToRemove, index == 0);
                        if (rowDataComparator.compare(duplicateRowDataOfNeedToRemove, currentMaxOrMinRowData) != 0) {
                            break;
                        }
                    }
                    this.rowDataList.set(index, duplicateRowDataOfNeedToRemove);
                }
            } else {
                // 不做改变
            }
        }

        if (currentMaxOrMinRowData != null) {
            currentMaxOrMinRowData = Utils.fromRowDataToArrayRowData(currentMaxOrMinRowData);
            RowValues duplicateRowDataOfNeedToRemove = null;//czh原来的代码RowData duplicateRowDataOfNeedToRemove = currentMaxOrMinRowData;
            // 当前的cursor消费一行记录，往前移动，如果有需要，还要去重
            while (true) {
                duplicateRowDataOfNeedToRemove = this.sortingCursorList.get(indexOfCurrentMaxOrMinRowData).next();//,当前值返回给用户,获取新值,设置到rowDataList中
                if (duplicateRowDataOfNeedToRemove == null) {//[为null或者不等于上一个值则为新值]
                    break;
                }
                duplicateRowDataOfNeedToRemove = wrapAndBuildColumnIndexToIndexInCursorMapIfNeed(duplicateRowDataOfNeedToRemove, indexOfCurrentMaxOrMinRowData == 0);
                if (!this.allowDuplicated) {//去重是指前面next一次之后获取的数据duplicateRowDataOfNeedToRemove进行去重,不是针对currentMaxOrMinRowData
                    super.initComparator(orderByList, duplicateRowDataOfNeedToRemove.getParentCursorMetaData());
                    if (rowDataComparator.compare(duplicateRowDataOfNeedToRemove, currentMaxOrMinRowData) != 0) {//[为null或者不等于上一个值则为新值]
                        break;
                    }
                } else {
                    break;//如果不去重只需要next一次
                }

            }
            this.rowDataList.set(indexOfCurrentMaxOrMinRowData, duplicateRowDataOfNeedToRemove);
        }

        setCurrent(currentMaxOrMinRowData);
        return currentMaxOrMinRowData;
    }

    private RowValues wrapAndBuildColumnIndexToIndexInCursorMapIfNeed(RowValues rowData, boolean indexIsLeftIndex0) {
        if (rowData == null) {
            return null;
        }
        if (columnIndexInTemplateCursorMetaDataToColumnIndexInRequestCursorMetaDataConvertor == null) {// 认为是初始化
            columnIndexInTemplateCursorMetaDataToColumnIndexInRequestCursorMetaDataConvertor = new ColumnIndexInTemplateCursorMetaDataToColumnIndexInRequestCursorMetaDataConvertor();
            columnIndexInTemplateCursorMetaDataToColumnIndexInRequestCursorMetaDataConvertor.wrapAndBuildColumnIndexInTemplateCursorMetaDataToColumnIndexInRequestCursorMetaDataMapIfNeed(rowData);
            columnIndexInTemplateCursorMetaDataToColumnIndexInRequestCursorMetaDataConvertor.reset();
            templateIndexIsLeftIndex0 = indexIsLeftIndex0;
        }
        if (templateIndexIsLeftIndex0 == indexIsLeftIndex0) {
            // template is leftNode and currentJoinRowData is leftNode
            // template is rightNode and currentJoinRowData is rightNode
            return rowData;
        } else {
            // template is leftNode but currentJoinRowData is rightNode
            // template is rightNode but currentJoinRowData is leftNode
            RowValues $rowData = columnIndexInTemplateCursorMetaDataToColumnIndexInRequestCursorMetaDataConvertor.wrapAndBuildColumnIndexInTemplateCursorMetaDataToColumnIndexInRequestCursorMetaDataMapIfNeed(rowData);
            //columnIndexInTemplateCursorMetaDataToColumnIndexInRequestCursorMetaDataConvertor.reset();
            return $rowData;
        }
    }

    private void setCurrent(RowValues current) {
        this.current = current;
    }

    public RowValues current() throws RuntimeException {
        return current;
    }

    public RowValues first() throws RuntimeException {
        for (int i = 0; i < this.sortingCursorList.size(); i++) {
            sortingCursorList.get(i).beforeFirst();
        }
        this.rowDataList.clear();
        this.inited = false;
        this.init();

        return next();
    }

    public void put(Record key, Record value) throws RuntimeException {
        throw new UnsupportedOperationException("should not be here");
    }

    public Cursor getCursor() {
        return cursor;
    }

    public Map<Record, DuplicateValueRowDataLinkedList> mgetRecordToDuplicateValueRowDataLinkedListMap(List<Record> keyRecordList, boolean prefixMatch, boolean keyFilterOrValueFilter) throws RuntimeException {

        throw new UnsupportedOperationException("should not be here");
    }

    public List<DuplicateValueRowDataLinkedList> mgetDuplicateValueRowDataLinkedListList(List<Record> keyRecordList, boolean prefixMatch, boolean keyFilterOrValueFilter) throws RuntimeException {
        throw new UnsupportedOperationException("should not be here");
    }

    public String toStringWithInden(int inden) {
        String tabTittle = GeneralUtil.getTab(inden);
        String tabContent = GeneralUtil.getTab(inden + 1);
        StringBuilder sb = new StringBuilder();

        GeneralUtil.printlnToStringBuilder(sb, tabTittle + "MergeSortedCursor ");
        GeneralUtil.printAFieldToStringBuilder(sb, "addOrderByItemAndSetNeedBuild", this.orderByList, tabContent);

        for (Cursor sub : this.sortingCursorList) {
            sb.append(sub.toStringWithInden(inden + 1));
        }

        return sb.toString();
    }

    public List<RuntimeException> close(List<RuntimeException> exs) {
        for (Cursor cursor : this.sortingCursorList) {
            if (cursor != null) {
                exs = cursor.close(exs);
            }
        }

        return exs;
    }

    public String toString() {
        return toStringWithInden(0);
    }
}
